package com.redepronik.negosysdis.invfac.controller;

import static com.redepronik.negosys.utils.Utils.iva;
import static com.redepronik.negosys.utils.Utils.newBigDecimal;
import static com.redepronik.negosys.utils.Utils.parametro;
import static com.redepronik.negosys.utils.Utils.presentaMensaje;
import static com.redepronik.negosys.utils.Utils.redondear;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.event.ActionEvent;

import org.primefaces.context.RequestContext;
import org.primefaces.event.CellEditEvent;
import org.primefaces.event.SelectEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;

import com.redepronik.negosys.invfac.entity.Bodega;
import com.redepronik.negosys.invfac.entity.Detalleegreso;
import com.redepronik.negosys.invfac.entity.Egreso;
import com.redepronik.negosys.invfac.entity.Entrada;
import com.redepronik.negosys.invfac.entity.Kardex;
import com.redepronik.negosys.invfac.entity.Local;
import com.redepronik.negosys.invfac.entity.Producto;
import com.redepronik.negosys.invfac.entityAux.CantidadFactura;
import com.redepronik.negosys.invfac.entityAux.FacturaReporte;
import com.redepronik.negosys.invfac.service.EgresoService;
import com.redepronik.negosys.invfac.service.KardexService;
import com.redepronik.negosys.invfac.service.LocalService;
import com.redepronik.negosys.invfac.service.ProductoService;
import com.redepronik.negosys.invfac.service.TipoDocumentoService;
import com.redepronik.negosys.rrhh.entity.Persona;
import com.redepronik.negosys.rrhh.service.ClienteService;
import com.redepronik.negosys.rrhh.service.EmpleadoService;
import com.redepronik.negosys.rrhh.service.PersonaService;
import com.redepronik.negosysdis.invfac.report.EgresoReport;

@Controller
@Scope("session")
public class PedidoBean implements Serializable {

	private static final long serialVersionUID = 1L;

	@Autowired
	private EgresoService egresoService;

	@Autowired
	private PersonaService personaService;

	@Autowired
	private ProductoService productoService;

	@Autowired
	private ClienteService clienteService;

	@Autowired
	private KardexService kardexService;

	@Autowired
	private LocalService localService;

	@Autowired
	private TipoDocumentoService tipoDocumentoService;

	@Autowired
	private EmpleadoService empleadoService;

	@Autowired
	private EgresoReport egresoReport;

	private Egreso egreso;
	private Persona cliente;

	private List<Producto> listaProductoBusqueda;
	private String criterioProductoBusqueda;
	private Producto producto;

	private List<FacturaReporte> facturaReportes;
	private FacturaReporte facturaReporte;
	private CantidadFactura cantidadFacturaCalculos;
	private CantidadFactura cantidadFacturaPresentar;

	private Integer cantidad;
	private BigDecimal nuevoPrecio;

	private Bodega bodega;
	private Integer fila;
	private List<Local> listaLocales;

	private String nombreVendedor;
	private boolean bnLocal;

	private List<Persona> listaClienteBusqueda;
	private String criterioClienteBusqueda;

	public PedidoBean() {
	}

	public void calcularDescuentoDolares() {
		egresoService.calcularDescuentoDolares(facturaReporte);
	}

	public void calcularDescuentoPorcentaje() {
		egresoService.calcularDescuentoPorcentaje(facturaReporte);
	}

	public void calcularPrecioCantidad() {
		egresoService.calcularPrecioCantidad(facturaReporte);
	}

	public void calcularPrecioPromocion() {
		egresoService
				.calcularPrecioPromocion(facturaReporte, producto.getIva());
	}

	public void calcularPrecioSubTotal() {
		egresoService.calcularDescuentoPorcentaje(facturaReporte);
	}

	public void calcularPrecioTotal() {
		egresoService.calcularPrecioTotal(facturaReporte);
	}

	public void calcularPrecioUnit() {
		egresoService.calcularPrecioUnit(facturaReporte);
	}

	public void cambiarCantidad() {
		if (cantidad <= 0)
			presentaMensaje(FacesMessage.SEVERITY_ERROR,
					"INGRESE UNA CANTIDAD MAYOR QUE CERO");
		else
			egresoService.recalcularCantidad(fila, facturaReportes,
					egreso.getDetalleegresos(), cantidadFacturaCalculos,
					cantidad, true);

		cantidad = null;
		fila = null;
	}

	public void cambiarDescuento() {
		egresoService.cambiarDescuentoFactura(cantidadFacturaCalculos,
				cantidadFacturaPresentar);
		egreso.setDescuento(cantidadFacturaCalculos.getDescuentoEgreso());
	}

	public void cambiarPrecio() {
		egresoService.recalcularPrecio(fila, bodega.getBodegaid(),
				facturaReportes, egreso.getDetalleegresos(),
				cantidadFacturaCalculos, nuevoPrecio, true);
		nuevoPrecio = null;
		fila = null;
	}

	public void cargarCliente(SelectEvent event) {
		cliente = clienteService.obtenerPorPersonaId(cliente.getPersonaid());
		egreso.setCliente(cliente.getCliente());
	}

	public void cargarProducto(SelectEvent event) {
		producto = productoService.obtenerPorProductoId(producto
				.getProductoid());
		facturaReporte.setProductoId(producto.getProductoid());
		Integer precioId = productoService.obtenerPvpPorProducto(producto
				.getTipoPrecioProductos());
		if (precioId == null) {
			precioId = producto.getTipoPrecioProductos().get(0)
					.getTipoprecioproductoid();
			presentaMensaje(FacesMessage.SEVERITY_WARN,
					"EL PRODUCTO NO TIENE CONFIGURADO EL PVP");
		}

		facturaReporte.setPrecioId(precioId);

		obtenerPrecio();
	}

	public boolean comprobar() {
		RequestContext context = RequestContext.getCurrentInstance();
		boolean bn = true;
		if (egreso.getCliente() == null) {
			bn = false;
			presentaMensaje(FacesMessage.SEVERITY_ERROR, "INGRESE UN CLIENTE");
		} else if (egreso.getDetalleegresos().isEmpty()) {
			bn = false;
			presentaMensaje(FacesMessage.SEVERITY_ERROR, "INGRESE PRODUCTOS");
		}
		context.addCallbackParam("error", bn);

		return bn;
	}

	public void comprobarLocal() {
		RequestContext context = RequestContext.getCurrentInstance();
		boolean bn = true;
		if (egreso.getLocal().getLocalid() == null) {
			bn = false;
			presentaMensaje(FacesMessage.SEVERITY_ERROR, "ESCOJA UN LOCAL");
		} else
			limpiarObjetosBusquedaProductos();

		context.addCallbackParam("error1", bn);

	}

	public void comprobarPrecioCosto() {
		if (facturaReporte.getProductoId() != 0) {
			BigDecimal precio = productoService.obtenerPorProductoId(
					facturaReporte.getProductoId()).getPrecio();
			if (facturaReporte.getPrecioUnitVenta().compareTo(precio) < 0)
				presentaMensaje(FacesMessage.SEVERITY_ERROR,
						"EL PRECIO NO DEBE SER MENOR AL PRECIO DE COSTO"
								+ precio);
			else {

				if (facturaReporte.getCantidad() != null)
					facturaReporte = egresoService
							.calcularTotales(facturaReporte);

				if (facturaReporte.getIva().compareToIgnoreCase("I") == 0)
					facturaReporte.setPrecioUnitIva(iva(facturaReporte
							.getPrecioUnitVenta()));
				else
					facturaReporte.setPrecioUnitIva(newBigDecimal());

				facturaReporte.setPrecioUnitTotal(redondear(facturaReporte
						.getPrecioUnitVenta().add(
								facturaReporte.getPrecioUnitIva())));

			}
		}
	}

	public void eliminarDetalle(ActionEvent actionEvent) {
		int posicion = egresoService.posicion(facturaReporte,
				egreso.getDetalleegresos(), true);
		if (posicion >= 0) {
			Detalleegreso de = egreso.getDetalleegresos().get(posicion);
			presentaMensaje(FacesMessage.SEVERITY_INFO, "ELIMINÓ EL PRODUCTO: "
					+ de.getProducto().getNombreimprimir());
			egreso.removeDetalleegreso(de);
			cantidadFacturaCalculos = egresoService.calcularCantidadFactura(
					cantidadFacturaCalculos, facturaReporte, "subtract");
			facturaReportes.remove(facturaReporte);
		}
	}

	public Integer getCantidad() {
		return cantidad;
	}

	public CantidadFactura getCantidadFacturaCalculos() {
		return cantidadFacturaCalculos;
	}

	public CantidadFactura getCantidadFacturaPresentar() {
		return egresoService.redondearCantidadFactura(cantidadFacturaPresentar,
				cantidadFacturaCalculos);
	}

	public Persona getCliente() {
		return cliente;
	}

	public String getCriterioClienteBusqueda() {
		return criterioClienteBusqueda;
	}

	public String getCriterioProductoBusqueda() {
		return criterioProductoBusqueda;
	}

	public Egreso getEgreso() {
		return egreso;
	}

	public FacturaReporte getFacturaReporte() {
		return facturaReporte;
	}

	public List<FacturaReporte> getFacturaReportes() {
		return facturaReportes;
	}

	public List<Persona> getListaClienteBusqueda() {
		return listaClienteBusqueda;
	}

	public List<Local> getListaLocales() {
		return listaLocales;
	}

	public List<Producto> getListaProductoBusqueda() {
		return listaProductoBusqueda;
	}

	public String getNombreVendedor() {
		return nombreVendedor;
	}

	public BigDecimal getNuevoPrecio() {
		return nuevoPrecio;
	}

	public Producto getProducto() {
		return producto;
	}

	@PostConstruct
	public void init() {
		String cedula = SecurityContextHolder.getContext().getAuthentication()
				.getName();
		Persona persona = personaService.obtenerPorCedula(cedula);
		setListaLocales(localService.obtenerPorCajero(cedula));
		setNombreVendedor(persona.getApellido().concat(" ")
				.concat(persona.getNombre()));
		limpiarObjetos();
	}

	public void insertar(ActionEvent actionEvent) {
		if (comprobar()) {
			egreso.setVendedorid(empleadoService
					.obtenerEmpleadoCargoPorCedulaAndCargo(
							SecurityContextHolder.getContext()
									.getAuthentication().getName(), 5));
			egreso.setPagado(false);
			egresoService.insertar(egreso, bodega);
			presentaMensaje(FacesMessage.SEVERITY_INFO, "INSERTÓ EL PEDIDO: "
					+ egreso.getCodigodocumento());
			limpiarObjetos();
		}

	}

	public void insertarDetalle(ActionEvent actionEvent) {
		if (producto == null)
			presentaMensaje(FacesMessage.SEVERITY_ERROR, "ESCOJA UN PRODUCTO");
		else {
			producto = productoService.obtenerPorProductoId(producto
					.getProductoid());

			Kardex kardex = kardexService.obtenerSaldoActual(producto.getEan(),
					bodega.getBodegaid());

			if (facturaReporte.getPrecioUnitVenta().compareTo(
					kardex.getPrecio()) < 0) {
				presentaMensaje(FacesMessage.SEVERITY_ERROR,
						"EL PRECIO UNITARIO NO DEBE SER MENOR AL PRECIO DE COSTO");
			} else if (facturaReporte.getCantidad() <= 0) {
				presentaMensaje(FacesMessage.SEVERITY_ERROR,
						"INGRESE UNA CANTIDAD MAYOR QUE CERO");
			} else {
				Detalleegreso detalleEgreso = new Detalleegreso();

				detalleEgreso.setProducto(producto);

				facturaReporte = egresoService.asignar(detalleEgreso,
						facturaReporte, egreso.getTipodocumento()
								.getTipodocumentoid());

				detalleEgreso.setCantidad(facturaReporte.getCantidad());
				detalleEgreso.setPreciocosto(kardex.getPrecio());
				detalleEgreso.setPrecioventa(facturaReporte
						.getPrecioUnitVenta());
				detalleEgreso
						.setDescuento(facturaReporte.getDescuentoDolares());
				detalleEgreso.setIva(producto.getIva());
				detalleEgreso.setPromocion(facturaReporte.isPromocion());
				detalleEgreso.setEliminar(facturaReporte.isEliminar());

				cantidadFacturaCalculos = egresoService
						.calcularCantidadFactura(cantidadFacturaCalculos,
								facturaReporte, "add");

				facturaReportes.add(facturaReporte);
				egreso.addDetalleegreso(detalleEgreso);

				presentaMensaje(FacesMessage.SEVERITY_INFO,
						"INSERTO EL PRODUCTO: " + producto.getNombreimprimir());
				limpiarObjetosBusquedaProductos();
				bnLocal = true;
			}
		}
	}

	public boolean isBnLocal() {
		return bnLocal;
	}

	public void limpiarObjetos() {
		bnLocal = false;
		cantidadFacturaCalculos = new CantidadFactura();
		cantidadFacturaCalculos = new CantidadFactura();
		cantidadFacturaPresentar = new CantidadFactura();
		cliente = new Persona();
		facturaReportes = new ArrayList<FacturaReporte>();
		facturaReporte = new FacturaReporte();
		producto = new Producto();

		egreso = new Egreso();
		egreso.setLocal(new Local());
		egreso.setEntradas(new ArrayList<Entrada>());
		egreso.setDetalleegresos(new ArrayList<Detalleegreso>());
		egreso.setTipodocumento(tipoDocumentoService.obtenerPorId(7));
		egreso.setCodigodocumento(egreso
				.getTipodocumento()
				.getAbreviatura()
				.concat("-")
				.concat(String.format("%010d",
						parametro.getSecuenciapedido() + 1)));

		if (listaLocales.size() == 1) {
			egreso.setLocal(listaLocales.get(0));
			obtenerBodega();
			bnLocal = true;
		}
	}

	public void limpiarObjetosBusquedaCliente() {
		criterioClienteBusqueda = new String();
		listaClienteBusqueda = new ArrayList<Persona>();
	}

	public void limpiarObjetosBusquedaProductos() {
		criterioProductoBusqueda = new String();
		// listaProductoBusqueda = new ArrayList<Producto>();
		producto = new Producto();
		facturaReporte = new FacturaReporte();
	}

	public void obtenerBodega() {
		Local local = localService.obtenerPorLocalId(egreso.getLocal()
				.getLocalid());
		// if (local.getBodegalocals() != null
		// && !local.getBodegalocals().isEmpty())
		bodega = local.getBodegalocals().get(0).getBodega();
	}

	public void obtenerClientesPorBusqueda() {
		listaClienteBusqueda = clienteService.obtener(criterioClienteBusqueda);
	}

	public void obtenerFila(CellEditEvent event) {
		fila = event.getRowIndex();
	}

	public void obtenerPrecio() {
		facturaReporte.setPrecioUnitVenta(productoService.calcularPrecio(
				producto, bodega.getBodegaid(), facturaReporte.getPrecioId()));

		facturaReporte.setIva(facturaReporte.isPromocion() ? "" : producto
				.getIva() ? "I" : "");

		if (facturaReporte.getCantidad() != null)
			facturaReporte = egresoService.calcularTotales(facturaReporte);

		facturaReporte.setPrecioUnitIva(facturaReporte.getIva()
				.compareToIgnoreCase("I") == 0 ? iva(facturaReporte
				.getPrecioUnitVenta()) : newBigDecimal());

		facturaReporte.setPrecioUnitTotal(redondear(facturaReporte
				.getPrecioUnitVenta().add(facturaReporte.getPrecioUnitIva())));
	}

	public void obtenerProductosPorBusqueda() {
		listaProductoBusqueda = productoService.obtenerPorLocal(
				criterioProductoBusqueda, egreso.getLocal().getLocalid());
	}

	public void setBnLocal(boolean bnLocal) {
		this.bnLocal = bnLocal;
	}

	public void setCantidad(Integer cantidad) {
		this.cantidad = cantidad;
	}

	public void setCantidadFacturaCalculos(
			CantidadFactura cantidadFacturaCalculos) {
		this.cantidadFacturaCalculos = cantidadFacturaCalculos;
	}

	public void setCantidadFacturaPresentar(
			CantidadFactura cantidadFacturaPresentar) {
		this.cantidadFacturaPresentar = cantidadFacturaPresentar;
	}

	public void setCliente(Persona cliente) {
		this.cliente = cliente;
	}

	public void setCriterioClienteBusqueda(String criterioClienteBusqueda) {
		this.criterioClienteBusqueda = criterioClienteBusqueda;
	}

	public void setCriterioProductoBusqueda(String criterioProductoBusqueda) {
		this.criterioProductoBusqueda = criterioProductoBusqueda;
	}

	public void setEgreso(Egreso egreso) {
		this.egreso = egreso;
	}

	public void setFacturaReporte(FacturaReporte facturaReporte) {
		this.facturaReporte = facturaReporte;
	}

	public void setFacturaReportes(List<FacturaReporte> facturaReportes) {
		this.facturaReportes = facturaReportes;
	}

	public void setListaClienteBusqueda(List<Persona> listaClienteBusqueda) {
		this.listaClienteBusqueda = listaClienteBusqueda;
	}

	public void setListaLocales(List<Local> listaLocales) {
		this.listaLocales = listaLocales;
	}

	public void setListaProductoBusqueda(List<Producto> listaProductoBusqueda) {
		this.listaProductoBusqueda = listaProductoBusqueda;
	}

	public void setNombreVendedor(String nombreVendedor) {
		this.nombreVendedor = nombreVendedor;
	}

	public void setNuevoPrecio(BigDecimal nuevoPrecio) {
		this.nuevoPrecio = nuevoPrecio;
	}

	public void setProducto(Producto producto) {
		this.producto = producto;
	}
}